package com.w.picture.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.w.picture.common.UniqueUsernameGenerator;
import com.w.picture.constans.UserConstant;
import com.w.picture.exception.BusinessException;
import com.w.picture.exception.ErrorCode;
import com.w.picture.exception.ThrowUtils;
import com.w.picture.manager.auth.StpKit;
import com.w.picture.mapper.UserMapper;
import com.w.picture.mode.dto.user.UserLoginRequest;
import com.w.picture.mode.dto.user.UserQueryRequest;
import com.w.picture.mode.dto.user.UserRegisterRequest;
import com.w.picture.mode.entity.User;
import com.w.picture.mode.enums.UserRoleEnum;
import com.w.picture.mode.vo.LoginUserVo;
import com.w.picture.mode.vo.UserVo;
import com.w.picture.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author w
 * @description 针对表【user(用户)】的数据库操作Service实现
 * @createDate 2024-12-15 16:12:35
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    private static final String SALT = "w-picture";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public long userRegister(UserRegisterRequest request) {
        // 1. 参数校验
        validateRequest(request);

        // 2. 校验用户名是否已存在
        ThrowUtils.throwIf(checkUserAccount(request.getUserAccount()), ErrorCode.PARAMS_ERROR, "用户名已存在");

        // 3. 验证两次输入的密码是否一致
        ThrowUtils.throwIf(!request.getUserPassword().equals(request.getCheckPassword()), ErrorCode.PARAMS_ERROR, "两次密码不一致");

        // 4. 密码加密
        String encryptedPassword = encryptPassword(request.getUserPassword());

        // 5. 构建并保存用户信息
        User user = createUserWithDetails(request, encryptedPassword);

        // 6. 设置邀请人信息（如果提供了有效的邀请码）
        setInviteUser(user, request.getInviteCode());

        // 7. 保存用户到数据库
        if (this.save(user)) {
            return user.getId(); // 注册成功，返回用户ID
        } else {
            return -1; // 保存失败，返回-1表示注册失败
        }
    }

    @Override
    public LoginUserVo userLogin(UserLoginRequest request, HttpServletRequest httpServletRequest) {
        // 1.参数校验
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(StrUtil.hasBlank(request.getUserAccount(), request.getUserPassword()),
                ErrorCode.PARAMS_ERROR, "用户名和密码不能为空");
        ThrowUtils.throwIf(request.getUserAccount().contains(" "), ErrorCode.PARAMS_ERROR, "用户名不能包含空格");

        // 2. 根据用户名查询用户
        User user = getUserByUserAccount(request.getUserAccount());
        boolean result = (
                user == null ||
                        !user.getUserPassword().equals(
                                encryptPassword(request.getUserPassword())
                        )
        );
        ThrowUtils.throwIf(result, ErrorCode.PARAMS_ERROR, "用户不存在/密码错误");

        // 3. 保存用户登录态 到 session
        httpServletRequest.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);

        // 增肌将用户登录信息存入到 Sa-Token 中 ,便于空间鉴权时使用,注意保证该用户信息 和 spring session 当中的过期时间一致
        StpKit.SPACE.login(user.getId());// 会话登录：参数填写要登录的账号id，建议的数据类型：long | int | String， 不可以传入复杂类型，如：User、Admin 等等
        StpKit.SPACE.getSession().set(UserConstant.USER_LOGIN_STATE, user); // 登录成功，设置登录态

        // 4.返回脱敏后的信息
        return getLoginUserVo(user);
    }

    @Override
    public User getLoginUser(HttpServletRequest request) {

        // 打印整个 session 内容
        Enumeration<String> attributeNames = request.getSession().getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String attributeName = attributeNames.nextElement();
            Object attributeValue = request.getSession().getAttribute(attributeName);
            System.out.println("Session Attribute: " + attributeName + " = " + attributeValue);
        }

        User user = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN_ERROR);

        // 追求性能直接返回session中的数据即可。只不过可能不是最新的。例如更新了权限
        User byId = this.getById(user.getId());
        ThrowUtils.throwIf(byId == null, ErrorCode.NOT_LOGIN_ERROR);
        return byId;
    }

    @Override
    public boolean userLogout(HttpServletRequest request) {
        User user = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        ThrowUtils.throwIf(user == null, ErrorCode.NOT_LOGIN_ERROR);
        // 清理掉当前用户的session 信息
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return true;
    }

    @Override
    public boolean isAdmin(User user) {
        if (user == null || StrUtil.isBlank(user.getUserRole())) {
            return false;
        }
        return UserConstant.ADMIN_ROLE.equals(user.getUserRole());
    }

    @Override
    public QueryWrapper<User> getQueryWrapper(UserQueryRequest userQueryRequest) {
        if (userQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR.getCode(), "请求参数为空");
        }
        Long id = userQueryRequest.getId();
        String userAccount = userQueryRequest.getUserAccount();
        String userName = userQueryRequest.getUserName();
        String userProfile = userQueryRequest.getUserProfile();
        String userRole = userQueryRequest.getUserRole();
        String sortField = userQueryRequest.getSortField();
        boolean asc = userQueryRequest.getSortOrder().equals("asc");
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ObjUtil.isNotNull(id), "id", id);
        queryWrapper.eq(StrUtil.isNotBlank(userRole), "userRole", userRole);
        queryWrapper.like(StrUtil.isNotBlank(userAccount), "userAccount", userAccount);
        queryWrapper.like(StrUtil.isNotBlank(userName), "userName", userName);
        queryWrapper.like(StrUtil.isNotBlank(userProfile), "userProfile", userProfile);
        queryWrapper.orderBy(StrUtil.isNotEmpty(sortField), asc, sortField);
        return queryWrapper;
    }


    @Override
    public UserVo getUserVo(User user) {
        if (user == null) {
            return null;
        }
        UserVo vo = new UserVo();
        BeanUtil.copyProperties(user, vo);
        return vo;
    }

    @Override
    public List<UserVo> getUserVoList(List<User> userList) {
        if (userList == null || userList.isEmpty()) {
            return Collections.emptyList();
        }
        return userList.stream().map(this::getUserVo).collect(Collectors.toList());
    }


    @Override
    public User getUserByUserAccount(String userAccount) {
        if (StrUtil.isBlank(userAccount)) {
            return null;
        }
        return this.getOne(new LambdaQueryWrapper<User>().eq(User::getUserAccount, userAccount));
    }

    // 校验请求参数的合法性
    private void validateRequest(UserRegisterRequest request) {
        ThrowUtils.throwIf(request == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(StrUtil.hasBlank(request.getUserAccount(), request.getUserPassword(), request.getCheckPassword()),
                ErrorCode.PARAMS_ERROR, "请求参数不能为空");
        ThrowUtils.throwIf(request.getUserAccount().length() < 4, ErrorCode.PARAMS_ERROR, "用户名过短");
        ThrowUtils.throwIf(request.getUserPassword().length() < 8, ErrorCode.PARAMS_ERROR, "密码过短");
        ThrowUtils.throwIf(request.getUserAccount().contains(" "), ErrorCode.PARAMS_ERROR, "用户名不能包含空格");
    }

    // 创建用户对象并设置基本信息
    public User createUserWithDetails(UserRegisterRequest request, String encryptedPassword) {
        User user = new User();
        user.setUserAccount(request.getUserAccount());
        user.setUserPassword(encryptedPassword);
        user.setUserName(UniqueUsernameGenerator.generateUniqueUsername());
        user.setUserRole(UserRoleEnum.USER.getValue());
        user.setShareCode(user.getUserName()); // 使用生成的用户名作为分享码
        user.setUserAvatar("https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png");

        return user;
    }

    // 设置邀请人信息（如果提供了有效的邀请码）
    private void setInviteUser(User user, String inviteCode) {
        if (StrUtil.isNotBlank(inviteCode)) {
            User inviter = getUserByShareCode(inviteCode);
            if (inviter != null) {
                user.setInviteUser(inviter.getId());
            }
        }
    }

    @Override
    public User getUserByShareCode(String shareCode) {
        if (StrUtil.isBlank(shareCode)) {
            return null;
        }
        return this.getOne(new LambdaQueryWrapper<User>().eq(User::getShareCode, shareCode));
    }

    @Override
    public boolean checkUserAccount(String userAccount) {
        // 原来的方法会增加逻辑删除的条件,导致校验失效.所以修改为自定义sql.不管是否删除用户名称必须唯一
        int num = this.baseMapper.checkUserAccount(userAccount);
        return num > 0;
    }

    @Override
    public String encryptPassword(String password) {
        return DigestUtil.sha256Hex((SALT + password).getBytes());
    }

    @Override
    public LoginUserVo getLoginUserVo(User user) {
        if (user == null) {
            return null;
        }
        return BeanUtil.copyProperties(user, LoginUserVo.class);
    }
}




